<?php

require_once 'PHPUnit/Framework/TestCase.php';
require_once 'Inspekt.php';

class Inspekt_Static extends PHPUnit_Framework_TestCase {

    protected $fixture;

    public function setUp() {
        $ascii_str = '';
        for ( $i = 0; $i < 256; $i++ ) {
            $ascii_str .= chr($i);
        }
        $this->fixture = array(
            'ascii'   => $ascii_str,
            'dosdir1' => 'c:/x',
            'dosdir2' => 'c:/Temp/x',
            'dosdir3' => '/x',
            'localdir' => 'localdir',
            'rootdir1' => '/root',
            'rootdir2' => '/root/',
            'bindir'   => '/binary/dir' . chr(27) . 'name',
            'two'      => 2,
            // https://www.paypal.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
            'testCCs'  => array(
                '378282246310005',
                '371449635398431',
                '378734493671000',
                '5610591081018250',
                '30569309025904',
                '38520000023237',
                '6011111111111117',
                '6011000990139424',
                '3530111333300000',
                '3566002020360505',
                '5555555555554444',
                '5105105105105100',
                '4111111111111111',
                '4012888888881881',
                '4222222222222',
                '5019717010103742',
                '6331101999990016',
            ),
        );
    }

    public function testGetAlnum() {
        $this->assertEquals(
            '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
            Inspekt::getAlnum( $this->fixture['ascii'] ) );
        $this->assertEquals(
            array(
                '',
                'abcd1234',
            ),
            Inspekt::getAlnum(
                array(
                    '',
                    ' abcd_1234 ',
                )
            )
        );
    }

    public function testGetAlpha() {
        $this->assertEquals(
            'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
            Inspekt::getAlpha( $this->fixture['ascii'] ) );
        $this->assertEquals(
            array(
                'abcd',
                '',
                'hithere',
            ),
            Inspekt::getAlpha(
                array(
                    'abcd1234',
                    M_E,
                    'hi, there',
                )
            )
        );
    }

    public function testGetDigits() {
        $this->assertEquals( '0123456789',
            Inspekt::getDigits( $this->fixture['ascii'] ) );
        $this->assertEquals(
            array(
                '2718',
                '',
            ),
            Inspekt::getDigits(
                array(
                    2.718,
                    'hello',
                )
            )
        );
    }

    public function testGetDir() {
        if ( preg_match( '/windows/i', php_uname() ) ) {
            $this->assertEquals( 'c:\\',
                Inspekt::getDir( $this->fixture['dosdir1'] ) );
            $this->assertEquals(
                array(
                    'c:/Temp',
                    '\\',
                ),
                Inspekt::getDir(
                    array(
                        $this->fixture['dosdir2'],
                        $this->fixture['dosdir3'],
                    )
                )
            );
        }
        else {
            $this->assertEquals( '.',
                Inspekt::getDir( $this->fixture['localdir'] ) );
            $this->assertEquals(
                array(
                    '/',
                    '/',
                    '/binary',
                ),
                Inspekt::getDir(
                    array(
                        $this->fixture['rootdir1'],
                        $this->fixture['rootdir2'],
                        $this->fixture['bindir'],
                    )
                )
            );
        }
    }

    public function testIsGreaterThan() {
        $this->assertTrue( Inspekt::isGreaterThan( 2, 1 ) );
        $this->assertTrue( Inspekt::isGreaterThan( 'b', 'a' ) );
        $this->assertFalse( Inspekt::isGreaterThan( 1, 2 ) );
        $this->assertFalse( Inspekt::isGreaterThan( 'a', 'b' ) );
    }

    public function testIsHex() {
        $this->assertTrue( Inspekt::isHex( '0123456789abcdefABCDEF' ) );
        $this->assertFalse( Inspekt::isHex( 'not hex' ) );
    }

    public function testIsHostname() {
        $this->assertTrue( Inspekt::isHostname( '1.2.3.4' ) );
        $this->assertFalse( Inspekt::isHostname( '1.2.3.400' ) );
        $this->assertTrue( Inspekt::isHostname( '1.2.3.4',
            ISPK_HOST_ALLOW_IP ) );
        $this->assertFalse( Inspekt::isHostname( '1.2.3.400',
            ISPK_HOST_ALLOW_IP ) );
        $this->assertFalse( Inspekt::isHostname( '1.2.3.4',
            ISPK_HOST_ALLOW_DNS ) );
        $this->assertFalse( Inspekt::isHostname( '1.2.3.400',
            ISPK_HOST_ALLOW_DNS ) );
        $this->assertTrue( Inspekt::isHostname( 'pear.php.net' ) );
        $this->assertTrue( Inspekt::isHostname( 'pear.php.net',
            ISPK_HOST_ALLOW_DNS ) );
        $this->assertFalse( Inspekt::isHostname( 'pear.php.net',
            ISPK_HOST_ALLOW_IP ) );
        $this->assertTrue( Inspekt::isHostname( 'localhost' ) );
        $this->assertFalse( Inspekt::isHostname( 'localhost',
            ISPK_HOST_ALLOW_IP ) );
        $this->assertFalse( Inspekt::isHostname( 'localhost',
            ISPK_HOST_ALLOW_DNS ) );
        $this->assertTrue( Inspekt::isHostname( 'localhost',
            ISPK_HOST_ALLOW_LOCAL ) );
    }

    public function testIsInt() {
        $this->assertTrue( Inspekt::isInt(0) );
        $this->assertTrue( Inspekt::isInt(42) );
        $this->assertFalse( Inspekt::isInt(M_PI) );
        $this->assertFalse( Inspekt::isInt( 'not_a_number' ) );
        $ten_thousand_point_oh = '10' . $locale['thousands_sep'] . '000'
            . $locale['decimal_point'] . '0';
        $this->assertTrue( Inspekt::isInt($ten_thousand_point_oh) );
    }

    /* isIp is more-or-less tested by testIsHostname(), and any isIp test would
     * mostly just be a test of ip2long, anyway.
     */

    public function testIsLessThan() {
        $this->assertTrue( Inspekt::isLessThan( 1, 2 ) );
        $this->assertTrue( Inspekt::isLessThan( 'a', 'b' ) );
        $this->assertFalse( Inspekt::isLessThan( 2, 1 ) );
        $this->assertFalse( Inspekt::isLessThan( 'b', 'a' ) );
    }

    public function testIsOneOf() {
        $this->assertTrue( Inspekt::isOneOf( 'one',
            array( 'one', 'two', 'three' ) ) );
        $this->assertFalse( Inspekt::isOneOf( 'four',
            array( 'one', 'two', 'three' ) ) );
    }

    public function testIsPhone() {
        $this->assertFalse( Inspekt::isPhone( '1234567' ) );
        $this->assertFalse( Inspekt::isPhone( '800-123-4567' ) );
        $this->assertTrue( Inspekt::isPhone( '8001234567' ) );
        $this->assertFalse( Inspekt::isPhone( '1111234567' ) );
        $this->assertTrue( Inspekt::isPhone( '8001234567', 'US' ) );
        $this->assertFalse( Inspekt::isPhone( '18001234567' ) );
    }

    public function testIsRegex() {
        $this->assertTrue( Inspekt::isRegex( 'hello',
            '/ \A [a-z]+ \z /xms' ) );
        $this->assertFalse( Inspekt::isRegex( 'hello',
            '/ \A [0-9]+ \z /xms' ) );
    }

    public function testIsUri() {
        // http://www.ietf.org/rfc/rfc2396.txt
        $this->assertTrue( Inspekt::isUri(
            'ftp://ftp.is.co.za/rfc/rfc1808.txt' ) );
        $this->assertTrue( Inspekt::isUri(
            'http://www.math.uio.no/faq/compression-faq/part1.html' ) );
        $this->assertTrue( Inspekt::isUri(
            'https://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles' ) );
    }

    public function testIsZip() {
        $this->assertTrue( Inspekt::isZip('12345') );
        $this->assertTrue( Inspekt::isZip('12345-6789') );
        $this->assertFalse( Inspekt::isZip('0') );
    }

    public function testNoPath() {
        $this->markTestIncomplete('devise some meaningful test of basename()');
    }

    public function testNoTags() {
        $this->assertEquals( 'no tags',
            Inspekt::noTags( '<strong>no <br />tags</strong>' ) );
        $this->assertEquals(
            array(
                'no tags',
                '3 < 4',
            ),
            Inspekt::noTags(
                array(
                    'no <? phpinfo(); ?>tags',
                    '3 < 4',
                )
            )
        );
    }

    public function testGetInt() {
        $this->assertEquals( 0, Inspekt::getInt( 'hello' ) );
        $this->assertEquals(
            array(
                -1,
                3,
            ),
            Inspekt::getInt(
                array(
                    -1,
                    M_PI,
                )
            )
        );
    }

    public function testGetPath() {
        $this->markTestIncomplete('devise some meaningful test of realpath()');
    }

    public function testIsAlnum() {
        $alnum_str = '0123456789'
            . 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
        $this->assertTrue( Inspekt::isAlnum($alnum_str) );
        for ( $i = 0; $i <= 47; $i++ ) {
            $this->assertFalse( Inspekt::isAlnum( chr($i) ) );
        }
        for ( $i = 58; $i <= 64; $i++ ) {
            $this->assertFalse( Inspekt::isAlnum( chr($i) ) );
        }
        for ( $i = 91; $i <= 96; $i++ ) {
            $this->assertFalse( Inspekt::isAlnum( chr($i) ) );
        }
        for ( $i = 123; $i <= 127; $i++ ) {
            $this->assertFalse( Inspekt::isAlnum( chr($i) ) );
        }
    }

    public function testIsAlpha() {
        $alpha_str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
        $this->assertTrue( Inspekt::isAlpha($alpha_str) );
        for ( $i = 0; $i <= 64; $i++ ) {
            $this->assertFalse( Inspekt::isAlpha( chr($i) ) );
        }
        for ( $i = 91; $i <= 96; $i++ ) {
            $this->assertFalse( Inspekt::isAlpha( chr($i) ) );
        }
        for ( $i = 123; $i <= 127; $i++ ) {
            $this->assertFalse( Inspekt::isAlpha( chr($i) ) );
        }
    }

    public function testIsBetween() {
        $this->assertTrue( Inspekt::isBetween( 1, 0, 2 ) );
        $this->assertTrue( Inspekt::isBetween( 1, 0, 2, 1 ) );
        $this->assertTrue( Inspekt::isBetween( 0, 0, 0 ) );
        $this->assertTrue( Inspekt::isBetween( 0, 0, 0, 1 ) );
        $this->assertTrue( Inspekt::isBetween( 1, 0, 2, 0 ) );
        $this->assertFalse( Inspekt::isBetween( 3, 0, 2, 0 ) );
    }

    public function testIsCcnum() {
        $this->assertFalse( Inspekt::isCcnum( 'not a cc number' ) );
        // too short...
        $this->assertFalse( Inspekt::isCcnum( '123456789012' ) );
        // too long...
        $this->assertFalse( Inspekt::isCcnum( '12345678901234567890' ) );
        // Dankort card (too short)
        $this->assertFalse( Inspekt::isCcnum( '76009244561' ) );
        foreach ( $this->fixture['testCCs'] as $ccnum ) {
            $this->assertTrue( Inspekt::isCcnum($ccnum) );
        }
    }

    public function testIsDate() {
        $this->assertTrue( Inspekt::isDate( date('Y-m-d') ) );
        $this->assertFalse( Inspekt::isDate( '0000-00-00' ) );
        $this->assertFalse( Inspekt::isDate( '1900-02-29' ) );
        $this->assertTrue( Inspekt::isDate( '2000-02-29' ) );
        // looks like checkdate() doesn't know about the Gregorian Reformation
        $this->assertTrue( Inspekt::isDate( '1752-09-03' ) );
    }

    public function testIsDigits() {
        $this->assertTrue( Inspekt::isDigits(0) );
        $this->assertTrue( Inspekt::isDigits(42) );
        $this->assertTrue( Inspekt::isDigits('3') );
        $this->assertFalse( Inspekt::isDigits(-1) );
        $this->assertFalse( Inspekt::isDigits(M_E) );
        $this->assertFalse( Inspekt::isDigits('hello') );
    }

    public function testIsEmailRFC3693() {
        // http://tools.ietf.org/html/rfc3696#page-5
        $this->markTestSkipped(
            'Inspekt does not validate email addresses according to RFC3693');
        $this->assertTrue( Inspekt::isEmail( 'Abc\@def@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( 'Fred\ Bloggs@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( 'Joe.\\Blow@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( '"Abc@def"@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( '"Fred Bloggs"@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( 'user+mailbox@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( 'customer/department=shipping@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( '$A12345@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( '!def!xyz%abc@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( '_somename@example.com' ) );
        $this->assertTrue( Inspekt::isEmail( "!#$%&'*+-/=?^_`.{|}~@example.com" ) );

        $local_part = '';
        $domain     = '.example.com';
        for ( $i = 1; $i <= 64; $i++ ) {
            $local_part .= 'a';
        }
        $n_iter = 255 - strlen('.example.com');
        for ( $i = 1; $i <= $n_iter; $i++ ) {
            $domain = 'a' . $domain;
        }
        $this->assertTrue( Inspekt::isEmail( "$local_part@$domain" ) );
        $this->assertFalse( Inspekt::isEmail( $local_part . 'a@' . $domain ) );
        $this->assertFalse( Inspekt::isEmail( $local_part . '@a' . $domain ) );
    }

    public function testIsFloat() {
        $this->assertTrue( Inspekt::isFloat(M_E) );
        $this->assertTrue( Inspekt::isFloat(4) );
        $this->assertTrue( Inspekt::isFloat(0) );
        $this->assertTrue( Inspekt::isFloat(-42) );
        $this->assertTrue( Inspekt::isFloat( -1 * M_PI ) );
        $this->assertFalse( Inspekt::isFloat('hello') );
        $this->assertFalse( Inspekt::isFloat(null) );
    }

}
